#include "StdAfx.h"
#include "SdManager.h"
#include <iostream>
#include <iomanip>
SdManager::CommandData::CommandData(ULONG BufferSize)
{
    length = sizeof(SDBuffer)+BufferSize;
    char *buf = new char[length];

    data = (SDBuffer *)buf;
    memset(data, 0, length);

    //Initialize
    SFFDISK_DEVICE_COMMAND_DATA &sdcd = GetCommandData();
    sdcd.HeaderSize = sizeof(SFFDISK_DEVICE_COMMAND_DATA);
    sdcd.Command = SFFDISK_DC_DEVICE_COMMAND;
    sdcd.ProtocolArgumentSize = sizeof(SDCMD_DESCRIPTOR);
    sdcd.DeviceDataBufferSize = BufferSize;
	

}

SdManager::CommandData::~CommandData()
{
    delete (char *)data;
}


void SdManager::CommandData::SetCommandParameter(
    SD_COMMAND_CODE Cmd,
    SD_COMMAND_CLASS CmdClass,
    SD_TRANSFER_DIRECTION TransferDirection,
    SD_TRANSFER_TYPE TransferType,
    SD_RESPONSE_TYPE ResponseType
    ) {
    SDCMD_DESCRIPTOR &Desc = data->Descriptor;
    Desc.Cmd = Cmd;
    Desc.CmdClass = CmdClass;
    Desc.TransferDirection = TransferDirection;
    Desc.TransferType = TransferType;
    Desc.ResponseType = ResponseType;
}
HANDLE OpenDevice(const wchar_t* drive)
{
    wchar_t volume[MAX_PATH];
    if(::GetVolumeNameForVolumeMountPoint(drive, volume,	MAX_PATH)){
        size_t length = wcslen(volume);
        if(volume[length-1] == L'\\'){
            volume[length-1] = 0;
        }
        HANDLE handle = ::CreateFile(volume,GENERIC_READ|GENERIC_WRITE,
                                     FILE_SHARE_READ|FILE_SHARE_WRITE
                                     ,NULL,OPEN_EXISTING,
                                     FILE_FLAG_NO_BUFFERING,NULL);
        if( INVALID_HANDLE_VALUE == handle){
            return NULL;
        }else{
            return handle;
        }
    }else{
        return NULL;
    }
}
void OutputBuffer(char* buffer, int size)
{
	for(int i = 0 ; i < size; ++i){
		std::cout << std::hex << ((buffer[i]&0xF0)>>4) << (buffer[i]&0x0F) << " ";
		if( i % 10 == 9){
			std::cout << std::endl;
		}
	}
	std::cout << std::endl;
}
BOOL SdManager::CommandData::Execute(const wchar_t* drive, LPDWORD pReturnBytes)
{
    HANDLE handle = OpenDevice(drive);
    if(handle){
		DWORD dummy;
		if(::DeviceIoControl(handle,IOCTL_SFFDISK_DEVICE_COMMAND, data, GetTotalSize(), 
			data, GetTotalSize(),pReturnBytes?pReturnBytes:&dummy, NULL)){
				OutputBuffer((char*)GetBuffer(), GetBufferSize());
				::CloseHandle(handle);
				return TRUE;
		}
		else{
			::CloseHandle(handle);
			return FALSE;
		}
	}else{
		return FALSE;
	}
}
BOOL SdManager::CheckSDCard(const wchar_t* drive)
{
    CommandData csd_packet(16);
    csd_packet.SetCommandParameter(SDCMD_SEND_CSD /*CMD9*/, SDCC_STANDARD, SDTD_READ, SDTT_CMD_ONLY, SDRT_2);
	return csd_packet.Execute(drive);
}
